package com.engine.salary.service.impl;

import cn.hutool.core.util.StrUtil;
import com.api.formmode.mybatis.util.SqlProxyHandle;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.biz.SalaryArchiveBiz;
import com.engine.salary.biz.SalaryArchiveItemBiz;
import com.engine.salary.biz.SalaryItemBiz;
import com.engine.salary.common.LocalDateRange;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.salaryarchive.config.ArchiveFieldConfig;
import com.engine.salary.entity.salaryarchive.dto.SalaryArchiveListDTO;
import com.engine.salary.entity.salaryarchive.dto.SalaryItemAdjustRecordListDTO;
import com.engine.salary.entity.salaryarchive.param.*;
import com.engine.salary.entity.salaryarchive.po.SalaryArchiveItemPO;
import com.engine.salary.entity.salaryarchive.po.SalaryArchivePO;
import com.engine.salary.entity.salaryitem.param.SalaryItemSearchParam;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.taxagent.param.TaxAgentQueryParam;
import com.engine.salary.entity.taxagent.po.TaxAgentPO;
import com.engine.salary.enums.UserStatusEnum;
import com.engine.salary.enums.auth.AuthFilterTypeEnum;
import com.engine.salary.enums.datacollection.UseEmployeeTypeEnum;
import com.engine.salary.enums.salaryarchive.SalaryArchiveFieldTypeEnum;
import com.engine.salary.enums.salaryarchive.SalaryArchiveItemAdjustReasonEnum;
import com.engine.salary.enums.salaryarchive.SalaryArchiveStatusEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.archive.SalaryArchiveItemMapper;
import com.engine.salary.mapper.salaryitem.SalaryItemMapper;
import com.engine.salary.service.*;
import com.engine.salary.sys.entity.vo.UploadConfigResponse;
import com.engine.salary.util.SalaryDateUtil;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.SalaryLoggerUtil;
import com.engine.salary.util.db.IdGenerator;
import com.engine.salary.util.db.MapperProxyFactory;
import com.engine.salary.util.excel.ExcelUtil;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.valid.ValidUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import weaver.hrm.User;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 薪资档案薪资项目
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
@Slf4j
public class SalaryArchiveItemServiceImpl extends Service implements SalaryArchiveItemService {

    private SalaryArchiveBiz salaryArchiveMapper = new SalaryArchiveBiz();
    private SalaryItemBiz salaryItemMapper = new SalaryItemBiz();
    private SalaryArchiveItemBiz salaryArchiveItemMapper = new SalaryArchiveItemBiz();

    private SalaryArchiveItemMapper getSalaryArchiveItemMapper() {
        return MapperProxyFactory.getProxy(SalaryArchiveItemMapper.class);
    }

    private SalaryItemMapper getSalaryItemMapper() {
        return SqlProxyHandle.getProxy(SalaryItemMapper.class);
    }


    @Override
    public SalaryArchiveItemPO getById(Long salaryArchiveItemId) {
        return salaryArchiveItemMapper.getById(salaryArchiveItemId);
    }

    private SalaryArchiveItemService getSalaryArchiveItemService(User user) {
        return ServiceUtil.getService(SalaryArchiveItemServiceImpl.class, user);
    }

    private TaxAgentService getTaxAgentService(User user) {
        return ServiceUtil.getService(TaxAgentServiceImpl.class, user);
    }

    private SalaryItemService getSalaryItemService(User user) {
        return ServiceUtil.getService(SalaryItemServiceImpl.class, user);
    }

    private SalaryArchiveService getSalaryArchiveService(User user) {
        return ServiceUtil.getService(SalaryArchiveServiceImpl.class, user);
    }

    private SalaryEmployeeService getSalaryEmployeeService(User user) {
        return ServiceUtil.getService(SalaryEmployeeServiceImpl.class, user);
    }

    /**
     * 获取未生效 lt
     *
     * @param salaryArchiveId
     * @param salaryItemIds
     * @return
     */
    private List<SalaryArchiveItemPO> getIneffectiveSalaryItems(Long salaryArchiveId, List<Long> salaryItemIds) {
        // 没有薪资项目时，给个不存在的，否则加载所有不合理
        salaryItemIds = CollectionUtils.isEmpty(salaryItemIds) ? Collections.singletonList(0L) : salaryItemIds;
        ArrayList<Long> salaryArchiveIds = new ArrayList<>();
        salaryArchiveIds.add(salaryArchiveId);
        return salaryArchiveItemMapper.getIneffectiveSalaryItems(SalaryArchiveItemQueryParam.builder()
                .salaryArchiveId(salaryArchiveId)
                .salaryArchivesIds(salaryArchiveIds)
                .salaryItemIds(salaryItemIds)
                .effectiveTime(new Date()).build());
    }

    private List<SalaryArchiveItemPO> getIneffectiveSalaryItems(Collection<Long> salaryArchivesIds, Collection<Long> salaryItemIds) {
        // 薪资档案id
        List<Long> salaryArchiveIds = CollectionUtils.isEmpty(salaryArchivesIds) ? Collections.singletonList(0L) : (List<Long>) salaryArchivesIds;
        // 没有薪资项目时，给个不存在的，否则加载所有不合理
        salaryItemIds = CollectionUtils.isEmpty(salaryItemIds) ? Collections.singletonList(0L) : salaryItemIds;
        return salaryArchiveItemMapper.getIneffectiveSalaryItems(SalaryArchiveItemQueryParam.builder()
                .salaryArchivesIds(salaryArchiveIds)
                .salaryItemIds(salaryItemIds)
                .effectiveTime(new Date()).build());
    }


    @Override
    public List<SalaryArchiveItemPO> getSalaryItemsBySalaryArchiveIdAndItemIds(Long salaryArchiveId, List<Long> salaryItemIds) {
        // 没有薪资项目时，给个不存在的，否则加载所有不合理
        salaryItemIds = CollectionUtils.isEmpty(salaryItemIds) ? Collections.singletonList(0L) : salaryItemIds;
        return salaryArchiveItemMapper.getEffectiveSalaryItems(SalaryArchiveItemQueryParam.builder()
                .salaryArchiveId(salaryArchiveId)
                .salaryItemIds(salaryItemIds)
                .build());
    }

    /**
     * 获取当前已生效 gt
     *
     * @param salaryArchiveId
     * @param salaryItemIds
     * @return
     */
    @Override
    public List<SalaryArchiveItemPO> getEffectiveSalaryItems(Long salaryArchiveId, List<Long> salaryItemIds) {
        // 没有薪资项目时，给个不存在的，否则加载所有不合理
        salaryItemIds = CollectionUtils.isEmpty(salaryItemIds) ? Collections.singletonList(0L) : salaryItemIds;
        return salaryArchiveItemMapper.getEffectiveSalaryItems(SalaryArchiveItemQueryParam.builder()
                .salaryArchiveId(salaryArchiveId)
                .salaryItemIds(salaryItemIds)
                .effectiveTime(new Date()).build());
    }

    /**
     * 获取薪资档案对应的当前生效的薪资项目
     *
     * @param salaryArchivesIds
     * @return
     */
    @Override
    public List<SalaryArchiveItemPO> getCurrentEffectiveItemList(Collection<Long> salaryArchivesIds, Collection<Long> salaryItemIds) {
        // 没有薪资项目时，给个不存在的，否则加载所有不合理
        salaryItemIds = CollectionUtils.isEmpty(salaryItemIds) ? Collections.singletonList(0L) : salaryItemIds;
        // 薪资档案id
        List<Long> salaryArchiveIds = CollectionUtils.isEmpty(salaryArchivesIds) ? Collections.singletonList(0L) : (List<Long>) salaryArchivesIds;
        List<SalaryArchiveItemPO> salaryArchiveItems = this.getEffectiveItemList(salaryArchiveIds, salaryItemIds);
        return salaryArchiveItems.stream()
                .collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(f -> f.getSalaryArchiveId() + "-" + f.getSalaryItemId()))), ArrayList::new));
    }

    /**
     * 获取当前已生效列表
     *
     * @param salaryArchiveIds
     * @param salaryItemIds
     * @return
     */
    private List<SalaryArchiveItemPO> getEffectiveItemList(Collection<Long> salaryArchiveIds, Collection<Long> salaryItemIds) {
        List<SalaryArchiveItemPO> salaryArchiveItems = Lists.newArrayList();
        List<List<Long>> partition = Lists.partition(Lists.newArrayList(salaryArchiveIds), 999);
        partition.forEach(part -> salaryArchiveItems.addAll(
                salaryArchiveItemMapper.getEffectiveSalaryItems(SalaryArchiveItemQueryParam.builder()
                        .salaryArchivesIds(part)
                        .salaryItemIds(salaryItemIds)
                        .effectiveTime(new Date()).build()))
        );
        // 解密
        return salaryArchiveItems;
    }


    @Override
    public Map<String, List<SalaryArchiveItemPO>> getEffectiveItemListMap(Collection<Long> salaryArchiveIds, boolean isNoNeedSalaryItem, Collection<Long> salaryItemIds) {
        // 没有薪资项目时，给个不存在的，否则加载所有不合理
        salaryItemIds = CollectionUtils.isEmpty(salaryItemIds) ? Collections.singletonList(0L) : salaryItemIds;
        // 薪资档案id
        List<Long> saIds = CollectionUtils.isEmpty(salaryArchiveIds) ? Collections.singletonList(0L) : (List<Long>) salaryArchiveIds;

        List<SalaryArchiveItemPO> salaryArchiveItems = Lists.newArrayList();

        if (isNoNeedSalaryItem) {
            salaryArchiveItems.addAll(getEffectiveItemList(saIds, salaryItemIds));
        } else {
            salaryArchiveItems = this.getEffectiveItemList(saIds, salaryItemIds);
        }

        return SalaryEntityUtil.group2Map(salaryArchiveItems, k -> k.getSalaryArchiveId() + "-" + k.getSalaryItemId());
    }

    @Override
    public Map<String, List<SalaryArchiveItemPO>> getIneffectiveItemListMap(Collection<Long> salaryArchiveIds, boolean isNoNeedSalaryItem, Collection<Long> salaryItemIds) {
        // 没有薪资项目时，给个不存在的，否则加载所有不合理
        salaryItemIds = CollectionUtils.isEmpty(salaryItemIds) ? Collections.singletonList(0L) : salaryItemIds;
        // 薪资档案id
        Collection<Long> saIds = CollectionUtils.isEmpty(salaryArchiveIds) ? Collections.singletonList(0L) : salaryArchiveIds;
        List<SalaryArchiveItemPO> salaryArchiveItems = Lists.newArrayList();

        if (isNoNeedSalaryItem) {
            salaryArchiveItems.addAll(getIneffectiveSalaryItems(saIds, salaryItemIds));
        } else {
            List<List<Long>> partition = Lists.partition((List) saIds, 1000);
            Collection<Long> finalSalaryItemIds = salaryItemIds;
            partition.forEach(part -> {
                salaryArchiveItems.addAll(getIneffectiveSalaryItems(saIds, finalSalaryItemIds));
            });

        }

        return SalaryEntityUtil.group2Map(salaryArchiveItems, k -> k.getSalaryArchiveId() + "-" + k.getSalaryItemId());
    }

    @Override
    public String editSingleSalaryItem(SalaryArchiveItemSaveParam salaryArchiveItemSaveParam) {
        // 检查参数
        SalaryArchiveItemSaveParam.checkParam(salaryArchiveItemSaveParam);

        Long salaryArchiveId = salaryArchiveItemSaveParam.getSalaryArchiveId();
        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItems = getCanAdjustSalaryItems();
        Map<Long, SalaryItemPO> salaryItemMap = SalaryEntityUtil.convert2Map(salaryItems, SalaryItemPO::getId);
        // 待处理薪资项目
        List<SalaryArchiveItemDetailSaveParam> salaryArchiveItems = salaryArchiveItemSaveParam.getSalaryArchiveItems().stream()
                .filter(e -> salaryItemMap.containsKey(e.getSalaryItemId()))
                .collect(Collectors.toList());
        List<Long> salaryItemIds = salaryArchiveItems.stream().map(SalaryArchiveItemDetailSaveParam::getSalaryItemId).collect(Collectors.toList());
        // 薪资档案
        SalaryArchivePO salaryArchive = salaryArchiveMapper.getById(salaryArchiveId);
        if (salaryArchive != null) {
            // 停薪列表禁止操作
            boolean isDisabled = salaryArchive.getRunStatus().equals(SalaryArchiveStatusEnum.STOP_FROM_PENDING.getValue()) ||
                    salaryArchive.getRunStatus().equals(SalaryArchiveStatusEnum.STOP_FROM_SUSPEND.getValue());
            if (isDisabled) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(115437, "停薪列表禁止操作"));
            }
            SalaryArchiveItemPO salaryArchiveItem = null;
            if (salaryArchiveItemSaveParam.getSalaryArchiveItemId() != null) {
                salaryArchiveItem = salaryArchiveItemMapper.getById(salaryArchiveItemSaveParam.getSalaryArchiveItemId());
                if (salaryArchiveItem == null || !salaryArchiveItem.getSalaryArchiveId().equals(salaryArchiveId)) {
                    throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100428, "该薪资档案的薪资项目的调整记录不存在"));
                }
                if (salaryArchiveItemSaveParam.getSalaryArchiveItems().size() > 1) {
                    throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(149535, "单个调整不能处理多个薪资项目"));
                } else if (!salaryArchiveItems.get(0).getSalaryItemId().equals(salaryArchiveItem.getSalaryItemId())) {
                    throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(149539, "单个调薪的目标项目和调整明细项目id不一致"));
                }
            }
            // 构建更新PO
            SalaryArchiveItemPO updateSalaryArchiveItemPO = buildUpdateSalaryArchiveItemPO(salaryArchiveItemSaveParam, salaryArchiveItems, salaryItemIds, salaryArchiveItem);
            salaryArchiveItemMapper.updateIgnoreNull(updateSalaryArchiveItemPO);

            // 查询更新后的po
            SalaryArchiveItemPO saiNew = salaryArchiveItemMapper.getById(updateSalaryArchiveItemPO.getId());
            // 记录操作日志
            String name = SalaryI18nUtil.getI18nLabel(0, "编辑调薪记录");
            SalaryLoggerUtil.recordUpdateSingleLog(SalaryElogConfig.salaryArchiveItemAdjustLoggerTemplate,
                    saiNew.getId(),
                    name + ":" + saiNew.getId(),
                    name,
                    name + ":" + saiNew.getId(),
                    salaryArchiveItem,
                    saiNew,
                    user
            );
        }
        return StringUtils.EMPTY;
    }


    /**
     * @return null
     * @description 构建薪资档案中调薪的更新PO
     * @author Harryxzy
     * @date 2022/11/14 14:24
     */
    private SalaryArchiveItemPO buildUpdateSalaryArchiveItemPO(SalaryArchiveItemSaveParam salaryArchiveItemSaveParam, List<SalaryArchiveItemDetailSaveParam> salaryArchiveItems, List<Long> salaryItemIds, SalaryArchiveItemPO salaryArchiveItem) {
        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItems = getSalaryArchiveItemService(user).getCanAdjustSalaryItems();
        // 获取生效+未生效的数据
        List<SalaryArchiveItemPO> salaryItemsBySalaryArchiveIdAndItemIds = getSalaryItemsBySalaryArchiveIdAndItemIds(salaryArchiveItemSaveParam.getSalaryArchiveId(), salaryItemIds);
        // 获取当前已生效数据
//        List<SalaryArchiveItemPO> effectiveSalaryItems = getEffectiveSalaryItems(salaryArchiveItemSaveParam.getSalaryArchiveId(), salaryItemIds);
        // 待保存生效时间
        Date saveEffectiveTime = salaryArchiveItemSaveParam.getEffectiveTime();
        salaryArchiveItems.forEach(e -> {
            // 已生效
//            List<SalaryArchiveItemPO> effectiveList = effectiveSalaryItems.stream().filter(i -> i.getSalaryItemId().equals(e.getSalaryItemId())).collect(Collectors.toList());
            // 当前已生效
//            SalaryArchiveItemPO effectiveSalaryItem = CollectionUtils.isNotEmpty(effectiveList) && effectiveList.size() > 0 ? effectiveList.get(0) : null;
            List<SalaryArchiveItemPO> list = salaryItemsBySalaryArchiveIdAndItemIds.stream().filter(i -> i.getSalaryItemId().equals(e.getSalaryItemId())).collect(Collectors.toList());
            // 判断该薪资项目是否是数字
            Optional<SalaryItemPO> optional = salaryItems.stream().filter(i -> i.getId().equals(e.getSalaryItemId())).findFirst();

            if (optional.isPresent()) {
                SalaryItemPO salaryItemPO = optional.get();
                boolean isNotNumber = salaryItemPO.getDataType().equals(SalaryArchiveFieldTypeEnum.NUMBER.getValue()) && StringUtils.isNotEmpty(e.getAdjustValue()) && !Pattern.matches(SalaryEntityUtil.NUMBER_REGEX, e.getAdjustValue());
                if (isNotNumber) {
                    throw new SalaryRunTimeException(salaryItemPO.getName() + ":" + SalaryI18nUtil.getI18nLabel(100581, "请输入数字"));
                }
            }

            // 修改了生效日期
            if (!salaryArchiveItemSaveParam.getEffectiveTime().equals(salaryArchiveItem.getEffectiveTime())) {
                boolean isEffectiveTimeRepeat = list.stream().anyMatch(it -> it.getEffectiveTime().equals(saveEffectiveTime));
                if (isEffectiveTimeRepeat) {
                    throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(153539, "已经存在该生效日期的调整记录，请修改生效日期"));
                }
            }

            // 1.检验是否可以调整
//            if (effectiveSalaryItem != null) {
            // 当前已经生效的时间
//                Date effectiveTime = effectiveSalaryItem.getEffectiveTime();
            // 1.1 如果保存的生效日期早于<当前已生效
//                if (saveEffectiveTime.before(effectiveTime)) {
//                    if(salaryArchiveItemSaveParam.getCanOperator() == Boolean.TRUE){
//                        throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100429, "生效日期不可早于当前已生效的调整日期"));
//                    }
//                    // 仅可编辑说明
//                    salaryArchiveItemMapper.updateIgnoreNull( SalaryArchiveItemPO.builder().id(salaryArchiveItemSaveParam.getSalaryArchiveItemId())
//                            .description(salaryArchiveItemSaveParam.getDescription()).build());
//                }
//            }
        });
        return SalaryArchiveItemPO.builder().id(salaryArchiveItemSaveParam.getSalaryArchiveItemId()).effectiveTime(salaryArchiveItemSaveParam.getEffectiveTime()).adjustReason(salaryArchiveItemSaveParam.getAdjustReason())
                .description(salaryArchiveItemSaveParam.getDescription()).itemValue(salaryArchiveItemSaveParam.getSalaryArchiveItems().get(0).getAdjustValue()).build();
    }


    @Override
    public List<SalaryArchiveItemPO> getCurrentEffectiveItemListIngoreValue(Collection<Long> salaryArchivesIds, List<Long> salaryItemIds) {
        // 没有薪资项目时，给个不存在的，否则加载所有不合理
        salaryItemIds = CollectionUtils.isEmpty(salaryItemIds) ? Collections.singletonList(0L) : salaryItemIds;
        // 薪资档案id
        List<Long> salaryArchiveIds = CollectionUtils.isEmpty(salaryArchivesIds) ? Collections.singletonList(0L) : (List<Long>) salaryArchivesIds;

        List<SalaryArchiveItemPO> salaryArchiveItems = Lists.newArrayList();
        List<List<Long>> partition = Lists.partition(Lists.newArrayList(salaryArchiveIds), 999);
        List<Long> finalSalaryItemIds = salaryItemIds;
        partition.forEach(part -> salaryArchiveItems.addAll(salaryArchiveItemMapper.getEffectiveSalaryItems(SalaryArchiveItemQueryParam.builder()
                .salaryArchivesIds(finalSalaryItemIds)
                .salaryItemIds(finalSalaryItemIds)
                .effectiveTime(new Date()).build())));
        return salaryArchiveItems;
    }

    @Override
    public String getSalaryItemAdjustBeforeValue(SalaryItemAdjustBeforeParam adjustBeforeParam) {

        ValidUtil.doValidator(adjustBeforeParam);

        List<SalaryArchiveItemPO> archiveItemList;
        if (adjustBeforeParam.getSalaryArchiveItemId() == null) {
            archiveItemList = getEffectiveSalaryItems(adjustBeforeParam.getSalaryArchiveId(), Collections.singletonList(adjustBeforeParam.getSalaryItemId()));
        } else {
            SalaryArchiveItemPO salaryArchiveItem = salaryArchiveItemMapper.getById(adjustBeforeParam.getSalaryArchiveItemId());
            if (salaryArchiveItem == null) {
                return "";
            }
            // 如果不是当前记录的
            if (!salaryArchiveItem.getSalaryItemId().equals(adjustBeforeParam.getSalaryItemId())) {
                archiveItemList = getEffectiveSalaryItems(adjustBeforeParam.getSalaryArchiveId(), Collections.singletonList(adjustBeforeParam.getSalaryItemId()));
            } else {
                archiveItemList = salaryArchiveItemMapper.getIneffectiveSalaryItems(SalaryArchiveItemQueryParam.builder()
                        .salaryArchiveId(adjustBeforeParam.getSalaryArchiveId())
                        .salaryItemId(salaryArchiveItem.getSalaryItemId())
                        .effectiveTime(salaryArchiveItem.getEffectiveTime()).build());
            }
        }

        return CollectionUtils.isNotEmpty(archiveItemList) ? archiveItemList.get(0).getItemValue() : "";
    }

    @Override
    public String saveSalaryItem(SalaryArchiveItemSaveParam saveParam) {
        // 检查参数
        SalaryArchiveItemSaveParam.checkParam(saveParam);

        Long salaryArchiveId = saveParam.getSalaryArchiveId();
        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItems = getCanAdjustSalaryItems();
        // 待处理薪资项目
        List<SalaryArchiveItemDetailSaveParam> salaryArchiveItems = saveParam.getSalaryArchiveItems().stream().filter(e -> {
            Optional<SalaryItemPO> optional = salaryItems.stream().filter(i -> i.getId().equals(e.getSalaryItemId())).findFirst();
            return optional.isPresent();
        }).collect(Collectors.toList());
        List<Long> salaryItemIds = salaryArchiveItems.stream().map(SalaryArchiveItemDetailSaveParam::getSalaryItemId).collect(Collectors.toList());

        // 薪资档案
        SalaryArchivePO salaryArchive = salaryArchiveMapper.getById(salaryArchiveId);
        if (salaryArchive == null) {
            throw new SalaryRunTimeException("薪资档案不存在！");
        }


        // 获取当前已生效数据
        List<SalaryArchiveItemPO> effectiveSalaryItems = getEffectiveSalaryItems(salaryArchiveId, salaryItemIds);

        // 获取未生效数据
        List<SalaryArchiveItemPO> ineffectiveSalaryItems = getIneffectiveSalaryItems(salaryArchiveId, salaryItemIds);
        // 待保存生效时间
        Date saveEffectiveTime = saveParam.getEffectiveTime();
        // 当天
        Date today = new Date();
        // 当前时间
        Date nowTime = new Date();

        List<Long> effectiveSalaryItemDels = Lists.newArrayList();
        List<SalaryArchiveItemPO> salaryArchiveItemNews = Lists.newArrayList();
        salaryArchiveItems.forEach(e -> {
            // 已生效
            List<SalaryArchiveItemPO> effectiveList = effectiveSalaryItems.stream().filter(i -> i.getSalaryItemId().equals(e.getSalaryItemId())).collect(Collectors.toList());
            // 当前已生效
            SalaryArchiveItemPO effectiveSalaryItem = CollectionUtils.isNotEmpty(effectiveList) && effectiveList.size() > 0 ? effectiveList.get(0) : null;
            // 当前已生效的前一次调整
            SalaryArchiveItemPO effectiveBeforeSalaryItem = CollectionUtils.isNotEmpty(effectiveList) && effectiveList.size() > 1 ? effectiveList.get(1) : null;
            // 未生效
            Optional<SalaryArchiveItemPO> optionalIneffective = ineffectiveSalaryItems.stream().filter(i -> i.getSalaryItemId().equals(e.getSalaryItemId())).findFirst();
            SalaryArchiveItemPO ineffectiveSalaryItem = optionalIneffective.orElse(null);

            // 1.检验是否可以调整
            if (effectiveSalaryItem != null) {
                // 当前已经生效的时间
                Date effectiveTime = effectiveSalaryItem.getEffectiveTime();
                // 1.1 如果早于<当前已生效
                if (saveEffectiveTime.before(effectiveTime)) {
                    throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100429, "生效日期不可早于当前已生效的调整日期"));
                    // 1.2 如果等于当前已生效 fixme 日期比较可能有bug
                } else if (saveEffectiveTime.equals(effectiveTime)) {
                    if (effectiveBeforeSalaryItem != null && effectiveBeforeSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                        throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100432, "调整前后不可相同"));
                    }
                    if (ineffectiveSalaryItem != null && ineffectiveSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                        throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100434, "与未生效的调整后不可相同"));
                    }
                    // 1.3 如果>已经生效且<=今天
                } else if (saveEffectiveTime.after(effectiveTime) && !saveEffectiveTime.after(today)) {
                    if (effectiveSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                        throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100432, "调整前后不可相同"));
                    }
                    if (ineffectiveSalaryItem != null && ineffectiveSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                        throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100434, "与未生效的调整后不可相同"));
                    }
                    // 1.4 如果>今天
                } else if (saveEffectiveTime.after(today) && effectiveSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                    throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100432, "调整前后不可相同"));
                }
            } else if (ineffectiveSalaryItem != null && ineffectiveSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100434, "与未生效的调整后不可相同"));
            }
            // 2.数据处理
            if (effectiveSalaryItem != null && saveEffectiveTime.equals(effectiveSalaryItem.getEffectiveTime())) {
                effectiveSalaryItemDels.add(effectiveSalaryItem.getId());
            }
            if (ineffectiveSalaryItem != null && saveEffectiveTime.after(today)) {
                effectiveSalaryItemDels.add(ineffectiveSalaryItem.getId());
            }
            salaryArchiveItemNews.add(buildInsert(salaryArchive, e.getSalaryItemId(), e.getAdjustValue(), saveParam, nowTime));
        });

        // 落库处理
        if (CollectionUtils.isNotEmpty(effectiveSalaryItemDels)) {
            salaryArchiveItemMapper.deleteBatchIds(effectiveSalaryItemDels);
        }
        if (CollectionUtils.isNotEmpty(salaryArchiveItemNews)) {
            salaryArchiveItemMapper.batchInsert(salaryArchiveItemNews, user);
        }

        return StringUtils.EMPTY;
    }

    @Override
    public String checkSaveSalaryItem(SalaryArchiveItemSaveParam saveParam) {
        // 检查参数
        SalaryArchiveItemSaveParam.checkParam(saveParam);

        Long salaryArchiveId = saveParam.getSalaryArchiveId();
        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItems = getCanAdjustSalaryItems();
        // 待处理薪资项目
        List<SalaryArchiveItemDetailSaveParam> salaryArchiveItems = saveParam.getSalaryArchiveItems().stream().filter(e -> {
            Optional<SalaryItemPO> optional = salaryItems.stream().filter(i -> i.getId().equals(e.getSalaryItemId())).findFirst();
            return optional.isPresent();
        }).collect(Collectors.toList());
        List<Long> salaryItemIds = salaryArchiveItems.stream().map(SalaryArchiveItemDetailSaveParam::getSalaryItemId).collect(Collectors.toList());

        // 薪资档案
        SalaryArchivePO salaryArchive = salaryArchiveMapper.getById(salaryArchiveId);
        // 获取当前已生效数据
        List<SalaryArchiveItemPO> effectiveSalaryItems = getEffectiveSalaryItems(salaryArchiveId, salaryItemIds);

        // 获取未生效数据
        List<SalaryArchiveItemPO> ineffectiveSalaryItems = getIneffectiveSalaryItems(salaryArchiveId, salaryItemIds);
        // 待保存生效时间
        Date saveEffectiveTime = saveParam.getEffectiveTime();
        // 当天
        Date today = new Date();
        // 当前时间
        Date nowTime = new Date();

        List<Long> effectiveSalaryItemDels = Lists.newArrayList();
        List<SalaryArchiveItemPO> salaryArchiveItemNews = Lists.newArrayList();
        salaryArchiveItems.forEach(e -> {
            // 已生效
            List<SalaryArchiveItemPO> effectiveList = effectiveSalaryItems.stream().filter(i -> i.getSalaryItemId().equals(e.getSalaryItemId())).collect(Collectors.toList());
            // 当前已生效
            SalaryArchiveItemPO effectiveSalaryItem = CollectionUtils.isNotEmpty(effectiveList) && effectiveList.size() > 0 ? effectiveList.get(0) : null;
            // 当前已生效的前一次调整
            SalaryArchiveItemPO effectiveBeforeSalaryItem = CollectionUtils.isNotEmpty(effectiveList) && effectiveList.size() > 1 ? effectiveList.get(1) : null;
            // 未生效
            Optional<SalaryArchiveItemPO> optionalIneffective = ineffectiveSalaryItems.stream().filter(i -> i.getSalaryItemId().equals(e.getSalaryItemId())).findFirst();
            SalaryArchiveItemPO ineffectiveSalaryItem = optionalIneffective.orElse(null);

            // 1.检验是否可以调整
            if (effectiveSalaryItem != null) {
                // 当前已经生效的时间
                Date effectiveTime = effectiveSalaryItem.getEffectiveTime();
                // 1.1 如果早于<当前已生效
                if (saveEffectiveTime.before(effectiveTime)) {
                    throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100429, "生效日期不可早于当前已生效的调整日期"));
                    // 1.2 如果等于当前已生效 fixme 日期比较可能有bug
                } else if (saveEffectiveTime.equals(effectiveTime)) {
                    if (effectiveBeforeSalaryItem != null && effectiveBeforeSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                        throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100432, "调整前后不可相同"));
                    }
                    if (ineffectiveSalaryItem != null && ineffectiveSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                        throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100434, "与未生效的调整后不可相同"));
                    }
                    // 1.3 如果>已经生效且<=今天
                } else if (saveEffectiveTime.after(effectiveTime) && !saveEffectiveTime.after(today)) {
                    if (effectiveSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                        throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100432, "调整前后不可相同"));
                    }
                    if (ineffectiveSalaryItem != null && ineffectiveSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                        throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100434, "与未生效的调整后不可相同"));
                    }
                    // 1.4 如果>今天
                } else if (saveEffectiveTime.after(today) && effectiveSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                    throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100432, "调整前后不可相同"));
                }
            } else if (ineffectiveSalaryItem != null && ineffectiveSalaryItem.getItemValue().equals(e.getAdjustValue())) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100434, "与未生效的调整后不可相同"));
            }
        });

        return StringUtils.EMPTY;
    }

    /**
     * 插入
     *
     * @param salaryArchive
     * @param saveParam
     */
    private SalaryArchiveItemPO buildInsert(SalaryArchivePO salaryArchive, Long salaryItemId, String adjustValue, SalaryArchiveItemSaveParam saveParam, Date now) {
        return SalaryArchiveItemPO.builder()
                .salaryArchiveId(saveParam.getSalaryArchiveId())
                .employeeId(salaryArchive.getEmployeeId())
                .effectiveTime(saveParam.getEffectiveTime())
                .adjustReason(saveParam.getAdjustReason())
                .description(saveParam.getDescription())
                .salaryItemId(salaryItemId)
                // 调整后
                .itemValue(adjustValue)
                .operator((long) user.getUID())
                .operateTime(now)
                .createTime(now)
                .updateTime(now)
                .creator((long) user.getUID())
                .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                .build();
    }

    @Override
    public String deleteSalaryItem(Long salaryArchiveItemId) {
        SalaryArchiveItemPO salaryArchiveItem = salaryArchiveItemMapper.getById(salaryArchiveItemId);
        if (salaryArchiveItem == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98299, "参数错误，薪资项目不存在或已被删除"));
        }
//        if (salaryArchiveItem.getEffectiveTime().after(new Date())) {
        salaryArchiveItem.setDeleteType(1);
        // 删除未生效数据
        salaryArchiveItemMapper.updateById(salaryArchiveItem);
        // 记录日志
        String operateName = SalaryI18nUtil.getI18nLabel(0, "删除调薪记录");
        SalaryLoggerUtil.recordDeleteSingleLog(SalaryElogConfig.salaryArchiveItemAdjustLoggerTemplate,
                salaryArchiveItem.getId(),
                operateName + ":" + salaryArchiveItem.getId(),
                operateName,
                operateName,
                salaryArchiveItem,
                user);
//        } else {
//            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98299, "该薪资项目已生效不可删除"));
//        }
        return StringUtils.EMPTY;
    }

    /**
     * 获取所有可被引用的薪资项目
     *
     * @return
     */
    @Override
    public List<SalaryItemPO> getCanAdjustSalaryItems() {

        TaxAgentQueryParam param = TaxAgentQueryParam.builder().build();
        param.setFilterType(AuthFilterTypeEnum.QUERY_DATA);
        Collection<TaxAgentPO> taxAgentList = getTaxAgentService(user).listAuth(param);
        List<Long> taxAgentIds = SalaryEntityUtil.properties(taxAgentList, TaxAgentPO::getId, Collectors.toList());

        List<SalaryItemPO> canAdjustSalaryItems = salaryItemMapper.getCanAdjustSalaryItems();
        canAdjustSalaryItems = canAdjustSalaryItems.stream()
                .filter(item -> item.getSharedType() == null
                        || 0 == item.getSharedType()
                        || (StringUtils.isNotBlank(item.getTaxAgentIds()) && SalaryEntityUtil.judgeIntersection(taxAgentIds, Arrays.stream(item.getTaxAgentIds().split(",")).map(Long::valueOf).collect(Collectors.toList()))))
                .collect(Collectors.toList());
        return canAdjustSalaryItems;
    }


    @Override
    public PageInfo<SalaryItemAdjustRecordListDTO> salaryItemAdjustRecordListPage(SalaryItemAdjustRecordQueryParam queryParam, List<Long> salaryItemIds) {
        return salaryArchiveItemMapper.salaryItemAdjustRecordListPage(queryParam, salaryItemIds);
    }

    @Override
    public List<SalaryItemAdjustRecordListDTO> salaryItemAdjustRecordList(SalaryItemAdjustRecordQueryParam queryParam, List<Long> salaryItemIds) {
        return salaryArchiveItemMapper.salaryItemAdjustRecordList(queryParam, salaryItemIds);
    }

    @Override
    public XSSFWorkbook exportAdjustRecordList(SalaryItemAdjustRecordQueryParam queryParam) {
        // 1.工作簿名称
        String sheetName = SalaryI18nUtil.getI18nLabel(85368, "薪资项目调整记录");
        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItems = salaryItemMapper.getCanAdjustSalaryItems();
        String[] header = {
                SalaryI18nUtil.getI18nLabel(85429, "姓名"),
                SalaryI18nUtil.getI18nLabel(86187, "员工状态"),
                SalaryI18nUtil.getI18nLabel(86185, "部门"),
                SalaryI18nUtil.getI18nLabel(84960, "薪资项目"),
                SalaryI18nUtil.getI18nLabel(85433, "调整前"),
                SalaryI18nUtil.getI18nLabel(85434, "调整后"),
                SalaryI18nUtil.getI18nLabel(85431, "调整原因"),
                SalaryI18nUtil.getI18nLabel(85904, "生效日期"),
                SalaryI18nUtil.getI18nLabel(85435, "操作人"),
                SalaryI18nUtil.getI18nLabel(85436, "操作时间"),
                SalaryI18nUtil.getI18nLabel(84961, "备注")
        };
        // 2.表头
        List<Object> headerList = new ArrayList<>(Arrays.asList(header));

        // 3.表数据
        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItemList = getCanAdjustSalaryItems();
        List<Long> salaryItemIds = salaryItemList.stream().map(SalaryItemPO::getId).collect(Collectors.toList());
        //分权
        SalaryArchiveQueryParam archiveQueryParam = new SalaryArchiveQueryParam();
        archiveQueryParam.setFilterType(AuthFilterTypeEnum.QUERY_DATA);
        List<Long> salaryArchiveIds = getSalaryArchiveService(user).list(archiveQueryParam).stream().map(SalaryArchiveListDTO::getId).collect(Collectors.toList());
        queryParam.setSalaryArchiveIds(salaryArchiveIds);

        List<DataCollectionEmployee> employeeList = getSalaryEmployeeService(user).listAll(UseEmployeeTypeEnum.ALL);
        Map<Long, DataCollectionEmployee> employeeMap = SalaryEntityUtil.convert2Map(employeeList, DataCollectionEmployee::getEmployeeId);

        List<SalaryItemAdjustRecordListDTO> listResult = getSalaryArchiveItemService(user).salaryItemAdjustRecordList(queryParam, salaryItemIds);
        listResult = listResult.stream()
                .filter(r -> {
                    DataCollectionEmployee employee = employeeMap.getOrDefault(r.getEmployeeId(), new DataCollectionEmployee());
                    String username = queryParam.getUsername();
                    List<Long> departmentIds = queryParam.getDepartmentIds();
                    List<Long> positionIds = queryParam.getPositionIds();
                    String userstatus = queryParam.getUserstatus();
                    r.setUsername(employee.getUsername());
                    r.setDepartmentName(employee.getDepartmentName());
                    r.setEmployeeStatus(UserStatusEnum.getDefaultLabelByValue(Integer.parseInt(NumberUtils.isCreatable(employee.getStatus()) ? employee.getStatus() : "-1")));
                    r.setAdjustReason(SalaryArchiveItemAdjustReasonEnum.getDefaultLabelByValue(r.getAdjustReason()));
                    return (StringUtils.isBlank(username) || employee.getUsername().contains(username))
                            && (CollectionUtils.isEmpty(departmentIds) || departmentIds.contains(employee.getDepartmentId()))
                            && (CollectionUtils.isEmpty(positionIds) || positionIds.contains(employee.getJobtitleId()))
                            && (StringUtils.isBlank(userstatus) || Objects.equals(employee.getStatus(), userstatus))
                            && (CollectionUtils.isEmpty(positionIds) || positionIds.contains(employee.getJobtitleId()))
                            ;
                })
                .collect(Collectors.toList());
        SalaryI18nUtil.i18nList(listResult);


        List<SalaryItemAdjustRecordListDTO> listAll = salaryArchiveItemMapper.salaryItemAdjustRecordList(SalaryItemAdjustRecordQueryParam.builder().build(), salaryItemIds);
        // 人员信息赋值
        listResult.forEach(m -> {
            if (!org.springframework.util.CollectionUtils.isEmpty(listAll)) {
                listAll.removeIf(a -> a.getId().equals(m.getId()));
            }
            Optional<SalaryItemAdjustRecordListDTO> optional = listAll.stream().filter(f -> f.getSalaryArchiveId().equals(m.getSalaryArchiveId()) && f.getSalaryItemId().equals(m.getSalaryItemId())).findFirst();
            m.setAdjustBefore(optional.isPresent() ? optional.get().getAdjustAfter() : "");
        });
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        List<List<Object>> rows = new ArrayList<>();
        rows.add(headerList);
        for (SalaryItemAdjustRecordListDTO dto : listResult) {
            List<Object> row = new ArrayList<>();
            row.add(dto.getUsername());
            row.add(dto.getEmployeeStatus());
            row.add(dto.getDepartmentName());
            row.add(dto.getAdjustItem());
            row.add(dto.getAdjustBefore());
            row.add(dto.getAdjustAfter());
            row.add(dto.getAdjustReason());
            row.add(SalaryDateUtil.getFormatDate(dto.getEffectiveTime()));
            row.add(dto.getOperator());
            row.add(format.format(dto.getOperateTime()));
            row.add(dto.getDescription());
            rows.add(row);
        }

        return ExcelUtil.genWorkbookV2(rows, sheetName);
    }


    @Override
    public ArchiveFieldConfig getConfig() {
        List<SalaryItemPO> salaryItemPOList = getSalaryItemService(user).listByParam(SalaryItemSearchParam.builder().useInEmployeeSalary(1).build());
        return ArchiveFieldConfig.builder().salaryItems(salaryItemPOList).build();
    }

    @Override
    public UploadConfigResponse.Result parseConfig(ArchiveFieldConfig config) {
        UploadConfigResponse.Result result = UploadConfigResponse.Result.builder()
                .message("档案字段加载完毕")
                .success(new ArrayList<>())
                .warning(new ArrayList<>())
                .error(new ArrayList<>())
                .build();
        long uid = user.getUID();
        List<SalaryItemPO> salaryItemPOList = getSalaryItemService(user).listAll();
        Map<String, SalaryItemPO> nameMap = SalaryEntityUtil.convert2Map(salaryItemPOList, SalaryItemPO::getName);
        Map<String, SalaryItemPO> codeMap = SalaryEntityUtil.convert2Map(salaryItemPOList, SalaryItemPO::getCode);
        Optional.ofNullable(config.getSalaryItems())
                .orElse(new ArrayList<>())
                .forEach(itemPO -> {
                    try {


                        if (nameMap.containsKey(itemPO.getName())) {
                            SalaryItemPO salaryItemPO = nameMap.get(itemPO.getName());
                            if (!StrUtil.equals(salaryItemPO.getCode(), itemPO.getCode())) {
                                result.getWarning().add(String.format("警告，档案字段[%s]名称已存在,但项目code不一致,迁入code:%s,当前系统code：%s", itemPO.getName(), itemPO.getCode(), salaryItemPO.getCode()));
                            }
                            itemPO.setId(salaryItemPO.getId());
                            //不许修改code
                            itemPO.setCode(null);
                            itemPO.setCreator(uid);
                            getSalaryItemMapper().updateIgnoreNull(itemPO);
                        } else if (codeMap.containsKey(itemPO.getCode())) {
                            SalaryItemPO salaryItemPO = codeMap.get(itemPO.getCode());
                            if (!StrUtil.equals(salaryItemPO.getName(), itemPO.getName())) {
                                result.getWarning().add(String.format("警告，档案字段[%s]code已存在,但项目code不一致,迁入名称:%s,当前系统名称：%s", itemPO.getName(), itemPO.getName(), salaryItemPO.getName()));
                            }
                            itemPO.setId(salaryItemPO.getId());
                            //不许修改名字
                            itemPO.setName(null);
                            itemPO.setCreator(uid);
                            getSalaryItemMapper().updateIgnoreNull(itemPO);
                        } else {
                            itemPO.setId(IdGenerator.generate());
                            getSalaryItemMapper().insertIgnoreNull(itemPO);
                        }
                        result.getSuccess().add(String.format("成功，薪资项目[%s]加载成功", itemPO.getName()));
                    } catch (Exception e) {
                        log.error("{}字段加载异常，", itemPO.getName(), e);
                        result.getError().add(String.format("错误，档案字段[%s]加载异常，%s", itemPO.getName(), e.getMessage()));
                    }
                });

        return result;
    }

    @Override
    public List<SalaryArchiveItemPO> listByArchiveIdAndEffectiveTime(List<Long> salaryArchiveIds, LocalDateRange dateRange) {
        if (CollectionUtils.isEmpty(salaryArchiveIds)) {
            return Collections.emptyList();
        }
        List<SalaryArchiveItemPO> resultList = new ArrayList<>();
        List<List<Long>> partition = Lists.partition(salaryArchiveIds, 1000);
        partition.forEach(part -> {
            resultList.addAll(getSalaryArchiveItemMapper().listByArchiveIdAndEffectiveTime(part, dateRange));
        });
        return resultList;
    }
}
